﻿// -----------------------------------------------------------------------
// <copyright file="CheckersBoard.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;

namespace CheckersLogic
{
    public delegate void IllegalMove();

    public delegate void EndOfMatch(char winningSymbol); 

    public class CheckersGame
    {
        public static event IllegalMove ThisMoveIsIllegal;

        public static event EndOfMatch ThisIsTheEndOfTheMatch;

        public static bool HandlePlayerTurn(Player i_currentTurnPlayer, Player i_secondPlayer, GameBoard i_gameBoard, CheckersMove i_playerMove)
        {
            bool hasAnotherTurn = false;
          
            i_currentTurnPlayer.updatePlayerPawnsArray(i_playerMove);
            checkIfEndOfBoard(i_currentTurnPlayer, ref i_playerMove, i_gameBoard.Size);
            if (i_playerMove.isEatingMove)
            {
                i_secondPlayer.RemoveEatenPawn(i_playerMove);
                i_gameBoard.updatePlayerMoveInGameBoard(i_playerMove);
                hasAnotherTurn = CheckForAnotherEatingMove(ref i_currentTurnPlayer, i_gameBoard, i_playerMove);
            }
            else
            {
                i_gameBoard.updatePlayerMoveInGameBoard(i_playerMove);
            }

            return hasAnotherTurn;
        }

        public static void CheckForAvailableMoves(ref Player i_currentTurnPlayer, GameBoard i_gameBoard)
        {
            i_currentTurnPlayer.m_availbleMoves.Clear();

            foreach (CheckerCell currentCell in i_currentTurnPlayer.GetPlayerPawnsArray())
            {
                CheckForAvailableMovesAux(i_currentTurnPlayer, currentCell, i_gameBoard);
            }
        }

        public static void CheckForAvailableMovesAux(Player i_currentTurnPlayer, CheckerCell i_currentCell, GameBoard i_gameBoard)
        {
            Direction rowDirection;
            Direction doubleRowDirection;

            if (i_currentCell.PawnSymbol == 'O')
            {
                rowDirection = Direction.down;
                doubleRowDirection = Direction.doubleDown;         
            }
            else if (i_currentCell.PawnSymbol == 'X')
            {
                rowDirection = Direction.up;
                doubleRowDirection = Direction.doubleUp;
            }
            else
            {
                updateMovesArray(i_currentCell, i_gameBoard, Direction.up, Direction.doubleUp, Direction.left, Direction.doubleLeft, i_currentTurnPlayer);
                updateMovesArray(i_currentCell, i_gameBoard, Direction.up, Direction.doubleUp, Direction.right, Direction.doubleRight, i_currentTurnPlayer);
                rowDirection = Direction.down;
                doubleRowDirection = Direction.doubleDown;
            }

            updateMovesArray(i_currentCell, i_gameBoard, rowDirection, doubleRowDirection, Direction.left, Direction.doubleLeft, i_currentTurnPlayer);
            updateMovesArray(i_currentCell, i_gameBoard, rowDirection, doubleRowDirection, Direction.right, Direction.doubleRight, i_currentTurnPlayer);
        }

        private static void updateMovesArray(CheckerCell i_currentCell, GameBoard i_gameBoard, Direction i_rowDirection, Direction i_doubleRowDirection, Direction i_columnDirection, Direction i_doubleColumnDirection, Player i_currentTurnPlayer)
        {
            bool eatingMove = true;
            CellValue cellValue = checkCellValue(GetCellFromGameBoard(i_currentCell, i_gameBoard, i_rowDirection, i_columnDirection), i_gameBoard.Size);
            CellValue oppositeSymbolValue1, oppositeSymbolValue2;
            if (i_currentTurnPlayer.Symbol == 'X')
            {
                oppositeSymbolValue1 = CellValue.oValue;
                oppositeSymbolValue2 = CellValue.qValue;
            }
            else
            {
                oppositeSymbolValue1 = CellValue.xValue;
                oppositeSymbolValue2 = CellValue.kValue;
            }

            if (cellValue == oppositeSymbolValue1 || cellValue == oppositeSymbolValue2)
            {
                if (checkCellValue(GetCellFromGameBoard(i_currentCell, i_gameBoard, i_doubleRowDirection, i_doubleColumnDirection), i_gameBoard.Size) == CellValue.emptyValue)
                {
                    CheckersMove newMoveToAdd = new CheckersMove(i_currentCell, GetCellFromGameBoard(i_currentCell, i_gameBoard, i_doubleRowDirection, i_doubleColumnDirection), eatingMove, i_currentTurnPlayer.Symbol);
                    i_currentTurnPlayer.GetPlayerAvailableMovesArray().Add(newMoveToAdd);
                    newMoveToAdd.isEatingMove = eatingMove;
                    i_currentTurnPlayer.HasEatingMoves = eatingMove;
                }
            }
            else if (cellValue == CellValue.emptyValue)
            {
                CheckersMove newMoveToAdd = new CheckersMove(i_currentCell, GetCellFromGameBoard(i_currentCell, i_gameBoard, i_rowDirection, i_columnDirection), !eatingMove, i_currentTurnPlayer.Symbol);
                i_currentTurnPlayer.GetPlayerAvailableMovesArray().Add(newMoveToAdd);
            }
        }

        private static bool CheckForAnotherEatingMove(ref Player i_currentTurnPlayer, GameBoard i_gameboard, CheckersMove i_currentMove)
        {
            i_currentTurnPlayer.m_availbleMoves.Clear();
            i_currentTurnPlayer.HasEatingMoves = false;
            i_currentMove.toCell.PawnSymbol = i_currentMove.MoveSymbol;
            CheckForAvailableMovesAux(i_currentTurnPlayer, i_currentMove.toCell, i_gameboard);
            return i_currentTurnPlayer.m_availbleMoves.Count > 0 && i_currentTurnPlayer.HasEatingMoves;
        }

        private static CheckerCell GetCellFromGameBoard(CheckerCell i_currentCell, GameBoard i_gameBoard, Direction i_rowDirection, Direction i_columnDirection)
        {
            CheckerCell cellToReturn = null;
            if (!isOutOfBounds(i_currentCell, i_columnDirection, i_rowDirection, i_gameBoard.Size))
            {
                cellToReturn = i_gameBoard.GetCheckerCell((int)(i_currentCell.CellColumn - 'A') + (int)i_columnDirection, (int)(i_currentCell.CellRow - 'a') + (int)i_rowDirection);
            }

            return cellToReturn;
        }

        private static bool isOutOfBounds(CheckerCell i_cellToCheck, Direction i_columnDirection, Direction i_rowDirection, int i_gameBoardSize)
        {
            int columnPosition = (int)(i_cellToCheck.CellColumn - 'A' + i_columnDirection);
            int rowPosition = (int)(i_cellToCheck.CellRow - 'a' + i_rowDirection);
            return columnPosition >= i_gameBoardSize || columnPosition < 0 || rowPosition >= i_gameBoardSize || rowPosition < 0;
        }

        private static CellValue checkCellValue(CheckerCell i_cellToCheck, int i_gameBoardSize)
        {
            CellValue cellToCheckValue;
            if (i_cellToCheck == null)
            {
                cellToCheckValue = CellValue.outOfBounds;
            }
            else
            {
                switch (i_cellToCheck.PawnSymbol)
                {
                    case 'X': cellToCheckValue = CellValue.xValue;
                        break;
                    case 'O': cellToCheckValue = CellValue.oValue;
                        break;
                    case 'Q': cellToCheckValue = CellValue.qValue;
                        break;
                    case 'K': cellToCheckValue = CellValue.kValue;
                        break;
                    case ' ': cellToCheckValue = CellValue.emptyValue;
                        break;
                    default: cellToCheckValue = CellValue.badValue;
                        break;
                }
            }

            return cellToCheckValue;
        }

        public static CheckersMove InterpretateStringToMove(string i_moveToIterpretate, Player i_currentPlayer)
        {
            CheckerCell fromCell = new CheckerCell();
            CheckerCell toCell = new CheckerCell();
            char moveSymbol = ' ';
            int placeOfMoveInArray;
            bool isMoveLegal = true;
           
            fromCell.CellColumn = i_moveToIterpretate[0];
            fromCell.CellRow = i_moveToIterpretate[1];
            toCell.CellColumn = i_moveToIterpretate[3];
            toCell.CellRow = i_moveToIterpretate[4];
            placeOfMoveInArray = i_currentPlayer.FindPlaceInPawnArray(fromCell, ref isMoveLegal);
            if (isMoveLegal)
            {
                moveSymbol = i_currentPlayer.GetPlayerPawnsArray()[placeOfMoveInArray].PawnSymbol;
            }

            return new CheckersMove(fromCell, toCell, false, moveSymbol);
        }

        public static bool isInputMoveLegal(CheckersMove i_playerMoveToCheck, Player i_currentTurnPlayer)
        {
            bool inputMoveLegal = false;
            List<CheckersMove> playerAvailableMoves = new List<CheckersMove>();
            playerAvailableMoves = i_currentTurnPlayer.GetPlayerAvailableMovesArray();
            foreach (CheckersMove currentMove in playerAvailableMoves)
            {
                if (CheckersMove.isEqual(currentMove, i_playerMoveToCheck))
                {
                    if (i_currentTurnPlayer.HasEatingMoves)
                    {
                        if (currentMove.isEatingMove)
                        {
                            i_playerMoveToCheck.isEatingMove = true;
                            inputMoveLegal = true;
                            i_currentTurnPlayer.HasEatingMoves = true;
                            break;
                        }
                    }
                    else
                    {
                        inputMoveLegal = true;
                        break;
                    }
                }
            }

            return inputMoveLegal;
        }

        public static bool IsEndOfMatch(Player i_playerO, Player i_playerX)
        {
            bool isEndOfMatch = false;
            char winningSymbol = 'w';
            if (i_playerO.m_availbleMoves.Count == 0 && i_playerX.m_availbleMoves.Count != 0)
            {
                isEndOfMatch = true;
                winningSymbol = 'X';
            }
            else if(i_playerO.m_availbleMoves.Count != 0 && i_playerX.m_availbleMoves.Count == 0) 
            {
                isEndOfMatch = true;
                winningSymbol = 'O';
            }
            else if (i_playerO.m_availbleMoves.Count == 0 && i_playerX.m_availbleMoves.Count == 0)
            {
                isEndOfMatch = true;
                winningSymbol = 'T';
            }

            if (isEndOfMatch)
            {
                if (ThisIsTheEndOfTheMatch != null)
                {
                    ThisIsTheEndOfTheMatch.Invoke(winningSymbol);
                }
            }

            return isEndOfMatch;
        }

        public static void UpdateMatchResult(Player i_playerO, Player i_playerX, char i_winningPlayerSymbol)
        {
            if (i_winningPlayerSymbol == 'O')
            {
                i_playerO.VictoryAtrributes(i_playerX.GetPlayerPawnsArray());
            }
            else
            {
                i_playerX.VictoryAtrributes(i_playerO.GetPlayerPawnsArray());
            }
        }

        private static void checkIfEndOfBoard(Player i_currentTurnPlayer, ref CheckersMove i_moveToCheck, int i_gameboardSize)
        {
            int indexOfCellToUpdate;
            bool isMoveLegal = true;
            if (i_currentTurnPlayer.Symbol == 'O')
            {
                if ((int)i_moveToCheck.toCell.CellRow - 'a' == (i_gameboardSize - 1))
                {
                    indexOfCellToUpdate = i_currentTurnPlayer.FindPlaceInPawnArray(i_moveToCheck.toCell, ref isMoveLegal);
                    i_currentTurnPlayer.ChangePawnSymbolInArray(indexOfCellToUpdate, 'Q');
                    i_moveToCheck.MoveSymbol = 'Q';
                }
            }
            else
            {
                if ((int)i_moveToCheck.toCell.CellRow - 'a' == 0)
                {
                    indexOfCellToUpdate = i_currentTurnPlayer.FindPlaceInPawnArray(i_moveToCheck.toCell, ref isMoveLegal);
                    i_currentTurnPlayer.ChangePawnSymbolInArray(indexOfCellToUpdate, 'K');
                    i_moveToCheck.MoveSymbol = 'K';
                }
            }
        }

        public enum CellValue
        {
            xValue = 1,
            oValue = 2,
            qValue = 3,
            kValue = 4,
            emptyValue = 5,
            badValue = 6,
            outOfBounds = 7
        }

        public enum Direction
        {
            up = -1,
            down = 1,
            left = -1,
            right = 1,
            doubleUp = -2,
            doubleDown = 2,
            doubleLeft = -2,
            doubleRight = 2,
        }
    }
}